#include "dispatcher.hh"

Dispatcher::Dispatcher()
{
    _run = false;
    _localNetwork = Socket(Socket::TCP4, "127.0.0.1", 2424);
}

Dispatcher::Dispatcher(string address, int port)
{
    _run = false;
    _localNetwork = Socket(Socket::TCP4, address, port);
}

void Dispatcher::Start(list<ServerHandler *> servers)
{
    _servers = servers;
    cout << "Compute Server starting..." << endl;
    setRunning(true);
    if (!(init() && createThread(&dispatcher_starter, (void*)this)))
        cerr << "Compute Server cannot create main thread!" << endl;
    cout << "Compute Server started..." << endl;
}

void Dispatcher::Stop()
{
    setRunning(false);
    cout << "Compute Server stopping..." << endl;
    if (false == joinThread())
        destroyThread();
    cout << "Compute Server stopped" << endl;
}

void Dispatcher::loop()
{
    Socket *clientSocket;
    list<ServerHandler*>::iterator serverTmp;
    list<ServerHandler*>::iterator serverIt;
    Socket *serverSocket;
    Protocol clientNetwork;
    int minClients;
    int numServers;
    bool found;

    while (isRunning())
    {
        cout << "Running..." << endl;
        if (0 != (clientSocket = _localNetwork.accept()))
        {
            cout << "Compute Thread found!" << endl;
            clientNetwork.InitDispatcher(clientSocket);
            clientNetwork.SendConnectionConfirmation();
            serverSocket = 0;
            found = false;

            do
            {
                numServers = 0;
                minClients = (*(_servers.begin()))->GetClientNumber();
                for (serverIt = _servers.begin(); serverIt != _servers.end(); ++serverIt)
                    if ((*serverIt)->GetClientNumber() < minClients)
                    {
                        minClients = (*serverIt)->GetClientNumber();
                        numServers = 1;
                    }
                    else if ((*serverIt)->GetClientNumber() == minClients)
                        numServers++;
                numServers = rand() % numServers;
                for (serverIt = _servers.begin(); serverIt != _servers.end(); ++serverIt)
                    if ((*serverIt)->GetClientNumber() == minClients)
                    {
                        if (numServers == 0)
                        {
                            serverTmp = serverIt;
                            found = true;
                            break;
                        }
                        else
                            numServers--;
                    }
                if (found == true && 0 == (serverSocket = (*serverTmp)->Connect()))
                {
                    (*serverTmp)->Stop();
                    _servers.erase(serverTmp);
                }
            } while(0 == serverSocket && _servers.size() > 0);
            if (_servers.size() == 0)
            {
                cerr << "No server available, dispatcher stopping..." << endl;
                setRunning(false);
            }
            else
            {
                clientNetwork.SendServerInfo(string(serverSocket->getSaddr()->getAddress()), serverSocket->getSaddr()->getPort());
                delete serverSocket;
                delete clientSocket;
            }
        }
    }
}

bool Dispatcher::init()
{
    srand (time(NULL));

    _localNetwork.bind();
    _localNetwork.listen();

    return (true);
}

bool Dispatcher::isRunning()
{
    bool tmp;

    lock();
    tmp = _run;
    unlock();
    return (tmp);
}

void Dispatcher::setRunning(bool run)
{
    lock();
    _run = run;
    unlock();
}

void *dispatcher_starter(void *data)
{
    Dispatcher *classInstance = reinterpret_cast<Dispatcher*>(data);
    classInstance->loop();
    return (data);
}
